package com.soarsky.boteng;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.sccl.common.util.StringUtil;

public class ScaffoldGen {

	private static final String NULLABLE = "NULLABLE";//可空
	private static final String DECIMAL_DIGITS = "DECIMAL_DIGITS";//十进制位数
	private static final String COLUMN_SIZE = "COLUMN_SIZE";//字段长度
	private static final String TYPE_NAME = "TYPE_NAME";//类型名
	private static final String REMARKS="REMARKS";//注释
	private static final String DBSERVER = "sqlserver";//数据库类型
	private static final String COLUMN_NAME = "COLUMN_NAME";//字段名
	private static final String JDBC_USER = "jdbc.user";//用户名
	private static final String JDBC_PASSWORD = "jdbc.password";//密码
	private static final String JDBC_URL = "jdbc.url";//连接url
	private static final String JDBC_DRIVER = "jdbc.driver";//jdbc驱动
	private static final String JDBC_SCHEMA = "jdbc.schema";//数据库所有者
	private static final String CONFIG_PROPERTIES = "jdbc.properties";//配置文件名
	private final Log log = LogFactory.getLog(getClass());
	private Connection conn;//连接
	private String schema;//架构
	private DatabaseMetaData metaData;//元数据
	private final String pkgName;//包名
	private final String clzName;//类名
	private final String tblName;//表名
	/**
	 * 构造函数1
	 * @param pkgName
	 * @param tblName
	 */
	public ScaffoldGen(String pkgName, String tblName) {
		
		this(pkgName,tblName,tblName);
		
	}
	/**
	 * 构造函数2
	 * @param pkgName
	 * @param clzName
	 * @param tblName
	 */
	public ScaffoldGen(String pkgName, String clzName, String tblName) {
		this.pkgName = pkgName;
		this.clzName = StringUtils.capitalize(clzName);//首字母大写
		this.tblName = tblName.toUpperCase();//转换成大写
	}

	public void execute() throws SQLException {
		execute(false);
	}

	public void execute(boolean debug) throws SQLException {
		if (!initConnection()) {
			System.out.println("数据库连接失败!,请检查ClassPath路径下的配置文件" + CONFIG_PROPERTIES);
			return;
		}
		TableInfo tableInfo = parseDbTable(this.tblName);
		if (tableInfo == null) {
			return;
		}
		ScaffoldBuilder sf = new ScaffoldBuilder(this.pkgName, this.clzName, tableInfo);
		List<FileGenerator> list = sf.buildGenerators();
		for (FileGenerator gen : list) {
			 gen.execute(debug);
		}
	}
	/**
	 * 初始化数据库连接
	 * @return
	 */
	private boolean initConnection() {
		Configuration config;
		String driver = null;
		String url = StringUtils.EMPTY;
		String user = StringUtils.EMPTY;
		String password = StringUtils.EMPTY;
		String schema = StringUtils.EMPTY;
		try {
			config = new PropertiesConfiguration(CONFIG_PROPERTIES);
			driver = config.getString(JDBC_DRIVER);
			url = config.getString(JDBC_URL);
			user = config.getString(JDBC_USER);
			password = config.getString(JDBC_PASSWORD);
			schema = config.getString(JDBC_SCHEMA);
			if (StringUtil.isNotBlank(schema)) {
				this.schema = schema;
			}
			if (driver.toLowerCase().contains(DBSERVER)) {
				this.schema = "dbo";
			}
			if (StringUtil.isBlank(this.schema)) {
				this.schema = user.toUpperCase();
			}
			Class.forName(driver);
		} catch (ConfigurationException e1) {
			e1.printStackTrace();
			log.fatal("Jdbc连接配置文件不能找到 - " + CONFIG_PROPERTIES);
			return false;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			log.fatal("Jdbc 驱动不能找到 - " + driver);
			return false;
		}

		try {   
			  Properties props =new Properties();
              props.put("remarksReporting","true");//取得注解需传入参数
              props.put("user", user);
              props.put("password", password);
			conn = DriverManager.getConnection(url,props);
			if (conn == null) {
				log.fatal("数据库连接为空!");
				return false;
			}
			metaData = conn.getMetaData();
			if (metaData == null) {
				log.fatal("数据库元数据为空");
				return false;
			}
		} catch (SQLException e) {
			log.fatal("数据库连接失败!");
			e.printStackTrace();
		}
		return true;
	}
	/**
	 * 更具字段映射成表信息
	 * @param tableName
	 * @return
	 * @throws SQLException 
	 */
	private TableInfo parseDbTable(String tableName) throws SQLException {
		TableInfo tableInfo = new TableInfo(tableName);
		ResultSet rs = null;
		log.trace("解析表开始....");
		try {
			rs = metaData.getPrimaryKeys(null, schema, tableName);
			if (rs.next()) {
				String keyName = rs.getString(COLUMN_NAME);
				//String keyType = rs.getString(TYPE_NAME);
				ColumnInfo keyInfo = new ColumnInfo(keyName, "VARCHAR", 64,0, 20,"主键");
				tableInfo.setPrimaryKey(keyName);
				tableInfo.setParserKey(keyInfo.parseFieldName());
				tableInfo.addColumn(keyInfo);
			}
			else{
				System.out.println("没有查询表的主键!");
				return null;
			}
		} catch (SQLException e) {
			log.error("表：' " + tableName + "' 解析错误.");
			e.printStackTrace();
			return null;
		}
		log.info("主键: " + tableInfo.getPrimaryKey());

		try {
			
			rs = metaData.getColumns(conn.getCatalog(), schema, tableName, null);
			if (!rs.next()) {
				log.fatal("表 " + schema + "." + tableName + " 没找到.");
				return null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			while (rs.next()) {
				String columnName = rs.getString(COLUMN_NAME);
				String columnType = rs.getString(TYPE_NAME);
				int datasize = rs.getInt(COLUMN_SIZE);	
				int digits = rs.getInt(DECIMAL_DIGITS);
				int nullable = rs.getInt(NULLABLE);
				String remarks=rs.getString(REMARKS);
				ColumnInfo colInfo = new ColumnInfo(columnName, columnType, datasize, digits, nullable,remarks);
				log.info("DB column : " + colInfo);
				log.info("Java field : " + colInfo.parseFieldName() + " / " + colInfo.parseJavaType());
				tableInfo.addColumn(colInfo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			log.error("表： " + tableName + " 解析错误.");
		}
		log.trace("恭喜,解析完毕!");
		return tableInfo;
	}

}
